Table of Contents

  • 1  Preamble
    • 1.1  Imports
    • 1.2  Lists
    • 1.3  Formatting functions
    • 1.4  API call functions
  • 2  Data aquisition
    • 2.1  Fetch online data
    • 2.2  Format data
    • 2.3  Save data
  • 3  Check changes
    • 3.1  Load latest file
    • 3.2  Generate changelog
  • 4  Data visualisation
    • 4.1  Full data
    • 4.2  Card types
    • 4.3  Monsters
      • 4.3.1  Attributes
      • 4.3.2  Primary types
        • 4.3.2.1  Has effect discrimination
        • 4.3.2.2  Is pendulum discrimination
        • 4.3.2.3  By attribute
      • 4.3.3  Secondary types
        • 4.3.3.1  By attribute
        • 4.3.3.2  By secondary type
      • 4.3.4  Monster types
        • 4.3.4.1  By Attribute
        • 4.3.4.2  By primary type
        • 4.3.4.3  By secondary type
      • 4.3.5  Effect type
      • 4.3.6  ATK
      • 4.3.7  DEF
      • 4.3.8  Level/Rank
        • 4.3.8.1  ATK statistics
        • 4.3.8.2  DEF statistics
      • 4.3.9  Pendulum scale
        • 4.3.9.1  ATK statistics
        • 4.3.9.2  DEF statistics
        • 4.3.9.3  Level/Rank statistics
      • 4.3.10  Link
        • 4.3.10.1  ATK statistics
      • 4.3.11  Link Arrows
        • 4.3.11.1  By combination
        • 4.3.11.2  By unique
        • 4.3.11.3  By link
    • 4.4  Spell & Trap
      • 4.4.1  Properties
      • 4.4.2  Effect type
        • 4.4.2.1  Spell & Trap discrimination
    • 4.5  Archseries
      • 4.5.1  By card type
      • 4.5.2  By primary type
      • 4.5.3  By secondary type
      • 4.5.4  By monster type
      • 4.5.5  By property
    • 4.6  Artworks
      • 4.6.1  By card type
      • 4.6.2  By primary type
    • 4.7  Errata
      • 4.7.1  By card type
      • 4.7.2  By primary type
      • 4.7.3  By artwork
    • 4.8  TCG & OCG status
      • 4.8.1  TGC status
        • 4.8.1.1  By card type
        • 4.8.1.2  By monster type
        • 4.8.1.3  By archseries
      • 4.8.2  OCG status
        • 4.8.2.1  By card type
        • 4.8.2.2  By monster type
        • 4.8.2.3  By archseries
      • 4.8.3  TCG vs. OCG status
  • 5  HTML export
  • 6  Searches

Preamble¶

Imports¶

import glob
import os
import pandas as pd
import numpy as np
import seaborn as sns
%matplotlib inline
import matplotlib.pyplot as plt
from matplotlib.colors import LogNorm, Normalize
from matplotlib_venn import venn2
from datetime import datetime
from ast import literal_eval

Lists¶

# Attributes to split monsters query
attributes = ['DIVINE', 'LIGHT', 'DARK', 'WATER', 'EARTH', 'FIRE', 'WIND']

# API variables
api_url = 'https://yugipedia.com/api.php'

# Styling dictionaries
arrows_dict = {'Middle-Left': '\u2190', 'Middle-Right': '\u2192', 'Top-Left': '\u2196', 'Top-Center': '\u2191', 'Top-Right': '\u2197', 'Bottom-Left': '\u2199', 'Bottom-Center': '\u2193', 'Bottom-Right': '\u2198'}
card_colors = {'Effect Monster': '#FF8B53', 'Normal Monster': '#FDE68A', 'Ritual Monster': '#9DB5CC', 'Fusion Monster': '#A086B7', 'Synchro Monster': '#CCCCCC', 'Xyz Monster': '#000000', 'Link Monster': '#00008B', 'Pendulum Monster': 'r', 'Monster Card': '#FF8B53', 'Spell Card': '#1D9E74', 'Trap Card': '#BC5A84', 'Monster Token': '#C0C0C0', 'FIRE': '#fd1b1b', 'WATER': '#03a9e6', 'EARTH': '#060d0a', 'WIND': '#77bb58', 'DARK': '#745ea5', 'LIGHT': '#9d8047', 'DIVINE': '#7e6537', 'Level': '#f1a41f'}

Formatting functions¶

def extract_results(df):
    df = pd.DataFrame(df['query']['results']).transpose()
    df = pd.DataFrame(df['printouts'].values.tolist())
    return df

def extract_artwork(row):
    result = tuple()
    if 'Category:OCG/TCG cards with alternate artworks' in row:
        result += ('Alternate',)
    if 'Category:OCG/TCG cards with edited artworks' in row:
        result += ('Edited',)
    if result == tuple():
        return np.nan
    else:
        return result

def concat_errata(row):
    result = tuple()
    if row['Name errata']:
        result += ('Name',)
    if row['Type errata']:
        result += ('Type',)
    if result == tuple():
        return np.nan
    else:
        return result 
    
def format_df(input_df, input_errata_df):
    df = pd.DataFrame()
    if 'Name' in input_df.columns:
        df['Name'] = input_df['Name'].dropna().apply(lambda x: x[0])
    if 'Password' in input_df.columns:
        df['Password'] = input_df['Password'].dropna().apply(lambda x: x[0] if len(x)>0 else np.nan)
    if 'Card type' in input_df.columns:
        df['Card type'] = input_df['Card type'].dropna().apply(lambda x: x[0]['fulltext'] if len(x)>0 else np.nan)
    if 'Property' in input_df.columns:
        df['Property'] = input_df['Property'].dropna().apply(lambda x: x[0] if len(x)>0 else np.nan)
    if 'Primary type' in input_df.columns:
        df['Primary type'] = input_df['Primary type'].dropna().apply(lambda x: [i['fulltext'] for i in x] if len(x)>0 else []).apply(lambda y: list(filter(lambda z: z != 'Pendulum Monster', y)) if len(y)>0 else []).apply(lambda y: list(filter(lambda z: z != 'Effect Monster', y))[0] if len(y)>1 else (y[0] if len(y)>0 else np.nan))
    if 'Secondary type' in input_df.columns:
        df['Secondary type'] = input_df['Secondary type'].dropna().apply(lambda x: x[0]['fulltext'] if len(x)>0 else np.nan)
    if 'Attribute' in input_df.columns:
        df['Attribute'] = input_df['Attribute'].dropna().apply(lambda x: x[0]['fulltext'] if len(x)>0 else np.nan)
    if 'Monster type' in input_df.columns:
        df['Monster type'] = input_df['Monster type'].dropna().apply(lambda x: x[0]['fulltext'] if len(x)>0 else np.nan)
    if 'Level/Rank' in input_df.columns:
        df['Level/Rank'] = input_df['Level/Rank'].dropna().apply(lambda x: x[0] if len(x)>0 else np.nan)
    if 'ATK' in input_df.columns:
        df['ATK'] = input_df['ATK'].dropna().apply(lambda x: x[0] if len(x)>0 else np.nan)
    if 'DEF' in input_df.columns:
        df['DEF'] = input_df['DEF'].dropna().apply(lambda x: x[0] if len(x)>0 else np.nan)
    if 'Pendulum Scale' in input_df.columns:
        df['Pendulum Scale'] = input_df['Pendulum Scale'].dropna().apply(lambda x: str(x[0]) if len(x)>0 else np.nan)
    if 'Link' in input_df.columns:
        df['Link'] = input_df['Link'].dropna().apply(lambda x: str(x[0]) if len(x)>0 else np.nan)
    if 'Link Arrows' in input_df.columns:
        df['Link Arrows'] = input_df['Link Arrows'].dropna().apply(lambda x: tuple([arrows_dict[i] for i in sorted(x)]) if len(x)>0 else np.nan)
    if 'Effect type' in input_df.columns:
        df['Effect type'] = input_df['Effect type'].dropna().apply(lambda x: tuple(sorted([i['fulltext'] for i in x])) if len(x)>0 else np.nan)
    if 'Archseries' in input_df.columns:
        df['Archseries'] = input_df['Archseries'].dropna().apply(lambda x: tuple(sorted(x)) if len(x)>0 else np.nan)
    if 'Category' in input_df.columns:
        df['Artwork'] = input_df['Category'].dropna().apply(lambda x: [i['fulltext'] for i in x] if len(x)>0 else np.nan).apply(extract_artwork)
    # Erratas column
    if input_errata_df is not None and 'Page name' in input_df.columns:
        df['Errata'] = errata_df.merge(input_df['Page name'].dropna().apply(lambda x: x[0]).rename('Name'), right_on = 'Name', left_index = True).apply(concat_errata,axis = 1)
    #################
    if 'TCG status' in input_df.columns:
        df['TCG status'] = input_df['TCG status'].dropna().apply(lambda x: x[0]['fulltext'] if len(x)>0 else np.nan)
    if 'OCG status' in input_df.columns:
        df['OCG status'] = input_df['OCG status'].dropna().apply(lambda x: x[0]['fulltext'] if len(x)>0 else np.nan)
    if 'Modification date' in input_df.columns:
        df['Modification date'] = input_df['Modification date'].dropna().apply(lambda x: pd.Timestamp(int(x[0]['timestamp']), unit='s').ctime() if len(x)>0 else np.nan)
    
    return df

API call functions¶

def card_query(_password = True, _card_type = True, _property = True, _primary = True, _secondary = True, _attribute = True, _monster_type = True, _stars = True, _atk = True, _def = True, _scale = True, _link = True, _arrows = True, _effect_type = True, _archseries = True, _category = True, _tcg = True, _ocg = True, _date = True, _page_name = True):
    search_string = f'|?English%20name=Name'
    if _password:
        search_string += '|?Password'
    if _card_type:
        search_string += '|?Card%20type'
    if _property:    
        search_string += '|?Property'
    if _primary:
        search_string += '|?Primary%20type'
    if _secondary:
        search_string += '|?Secondary%20type'
    if _attribute:
        search_string += '|?Attribute'
    if _monster_type:
        search_string += '|?Type=Monster%20type'
    if _stars:
        search_string += '|?Stars%20string=Level%2FRank%20'
    if _atk:
        search_string += '|?ATK%20string=ATK'
    if _def:
        search_string += '|?DEF%20string=DEF'
    if _scale:
        search_string += '|?Pendulum%20Scale'
    if _link:
        search_string += '|?Link%20Rating=Link'
    if _arrows:
        search_string += '|?Link%20Arrows'
    if _effect_type:
        search_string += '|?Effect%20type'
    if _archseries:
        search_string += '|?Archseries'
    if _category:
        search_string += '|?category'
    if _tcg:
        search_string += '|?TCG%20status'
    if _ocg:
        search_string += '|?OCG%20status'
    if _date:
        search_string += '|?Modification%20date'
    if _page_name:
        search_string += '|?Page%20name'
    
    return search_string

def fetch_spell(spell_query, step = 5000, limit = 5000):
    print('Downloading Spells')
    spell_df = pd.DataFrame()
    for i in range(int(limit/step)):
        df = pd.read_json(f'{api_url}?action=ask&query=[[Concept:CG%20Spell%20Cards]]{spell_query}|limit%3D{step}|offset={i*step}|order%3Dasc&format=json')
        df = extract_results(df)
        print(f'Iteration {i+1}: {len(df.index)} results')
        spell_df = pd.concat([spell_df, df], ignore_index=True, axis=0)
        if len(df.index)<step:
            break
                
    print(f'- Total\n{len(spell_df.index)} results\n')
    
    return spell_df

def fetch_trap(trap_query, step = 5000, limit = 5000):
    print('Downloading Traps')
    trap_df = pd.DataFrame()
    for i in range(int(limit/step)):    
        df = pd.read_json(f'{api_url}?action=ask&query=[[Concept:CG%20Trap%20Cards]]{trap_query}|limit%3D{step}|offset={i*step}|order%3Dasc&format=json')
        df = extract_results(df)
        print(f'Iteration {i+1}: {len(df.index)} results')
        trap_df = pd.concat([trap_df, df], ignore_index=True, axis=0)
        if len(df.index)<step:
            break
                
    print(f'- Total\n{len(trap_df.index)} results\n')
    
    return trap_df

def fetch_monster(monster_query, step = 5000, limit = 5000):
    print('Downloading Monsters')
    monster_df = pd.DataFrame()
    for att in attributes:
        print(f"- {att}")
        for i in range(int(limit/step)):
            df = pd.read_json(f'{api_url}?action=ask&query=[[Concept:CG%20monsters]][[Attribute::{att}]]{monster_query}|limit%3D{step}|offset={i*step}|order%3Dasc&format=json')
            df = extract_results(df)
            print(f'Iteration {i+1}: {len(df.index)} results')
            monster_df = pd.concat([monster_df, df], ignore_index=True, axis=0)
            if len(df.index)<step:
                break
        
    print(f'- Total\n{len(monster_df.index)} results')
    
    return monster_df

def fetch_name_errata(limit = 1000):
    name_query_df = pd.read_json(f'{api_url}?action=ask&query=[[Category:Cards%20with%20name%20errata]]|limit={limit}|order%3Dasc&format=json')
    name_keys = list(name_query_df['query']['results'].keys())
    return pd.DataFrame(True, index = [i.split(':')[1].strip() for i in name_keys if 'Card Errata:' in i], columns = ['Name errata'])

def fetch_type_errata(limit = 1000):
    type_query_df = pd.read_json(f'{api_url}?action=ask&query=[[Category:Cards%20with%20card%20type%20errata]]|limit={limit}|order%3Dasc&format=json')
    type_keys = list(type_query_df['query']['results'].keys())
    return pd.DataFrame(True, index = [i.split(':')[1].strip() for i in type_keys if 'Card Errata:' in i], columns = ['Type errata'])

Data aquisition¶

Fetch online data¶

monster_query = card_query(_property = False)
st_query = card_query(_primary = False, _secondary = False, _attribute = False, _monster_type = False, _stars = False, _atk = False, _def = False, _scale = False, _link = False, _arrows = False)
# Timestamp
timestamp = pd.Timestamp.now().timestamp()
full_df = pd.DataFrame()

# Fetch Spell
spell_df = fetch_spell(st_query, step = 1000, limit = 3000)
full_df = pd.concat([full_df, spell_df], ignore_index=True, axis=0)

# Fetch Trap
trap_df = fetch_trap(st_query, step = 1000, limit = 3000)
full_df = pd.concat([full_df, trap_df], ignore_index=True, axis=0)
st_df = pd.concat([spell_df, trap_df], ignore_index=True, axis=0)

# Fetch Monster
monster_df = fetch_monster(monster_query, step = 1000, limit = 5000)
full_df = pd.concat([full_df, monster_df], ignore_index=True, axis=0)

# Fetch errata
errata_df = pd.concat([fetch_name_errata(), fetch_type_errata()], axis=1).fillna(False)
Downloading Spells
Iteration 1: 1000 results
Iteration 2: 1000 results
Iteration 3: 352 results
- Total
2352 results

Downloading Traps
Iteration 1: 1000 results
Iteration 2: 796 results
- Total
1796 results

Downloading Monsters
- DIVINE
Iteration 1: 9 results
- LIGHT
Iteration 1: 1000 results
Iteration 2: 613 results
- DARK
Iteration 1: 1000 results
Iteration 2: 1000 results
Iteration 3: 204 results
- WATER
Iteration 1: 827 results
- EARTH
Iteration 1: 1000 results
Iteration 2: 857 results
- FIRE
Iteration 1: 662 results
- WIND
Iteration 1: 758 results
- Total
7930 results

Format data¶

formatted_spell_df = format_df(spell_df, errata_df)
formatted_trap_df = format_df(trap_df, errata_df)
formatted_st_df = format_df(st_df, errata_df)
formatted_monster_df = format_df(monster_df, errata_df)
formatted_full_df = format_df(full_df, errata_df)
print('Data formated')
Data formated

Save data¶

formatted_full_df.to_csv(f'Data/All_cards_{int(timestamp)}.csv', index = False)
print('Data saved')
Data saved

Check changes¶

Load latest file¶

# Get list of files
list_of_files = sorted(glob.glob('Data/All_cards_*.csv'), key=os.path.getctime, reverse=True)
# Get second newest file if exist
if len(list_of_files)>1:
    latest_file = list_of_files[1]
    previous_df = pd.read_csv(latest_file, dtype=object)
    # Correct tuples
    previous_df['Effect type'] = previous_df['Effect type'].dropna().apply(literal_eval)
    previous_df['Link Arrows'] = previous_df['Link Arrows'].dropna().apply(literal_eval)
    previous_df['Archseries'] = previous_df['Archseries'].dropna().apply(literal_eval)
    previous_df['Artwork'] = previous_df['Artwork'].dropna().apply(literal_eval)
    previous_df['Errata'] = previous_df['Errata'].dropna().apply(literal_eval)
    print('File loaded')
else:
    print('No older files')
File loaded

Generate changelog¶

if previous_df is not None:
    changelog = previous_df.merge(formatted_full_df,indicator = True, how='outer').loc[lambda x : x['_merge']!='both'].sort_values('Name', ignore_index=True)
    changelog['_merge'].replace(['left_only','right_only'],['Old', 'New'], inplace = True)
    changelog.rename(columns={"_merge": "Version"}, inplace = True)
    nunique = changelog.groupby('Name').nunique()
    cols_to_drop = nunique[nunique < 2].dropna(axis=1).columns
    changelog = changelog.set_index('Name')[nunique > 1]
    changelog.drop(cols_to_drop, axis=1, inplace = True)
    changelog
else:
    print('No changes')

Data visualisation¶

Full data¶

formatted_full_df
Name Password Card type Property Primary type Secondary type Attribute Monster type Level/Rank ATK ... Pendulum Scale Link Link Arrows Effect type Archseries Artwork Errata TCG status OCG status Modification date
0 "A" Cell Breeding Device 34541863 Spell Card Continuous Spell Card NaN NaN NaN NaN NaN NaN ... NaN NaN NaN (Trigger Effect,) NaN NaN (Name,) Unlimited Unlimited Sat Nov 6 13:57:15 2021
1 "A" Cell Incubator 64163367 Spell Card Continuous Spell Card NaN NaN NaN NaN NaN NaN ... NaN NaN NaN (Continuous-like Effect, Trigger Effect) NaN NaN NaN Unlimited Unlimited Mon Jun 13 04:27:51 2022
2 "A" Cell Recombination Device 91231901 Spell Card Quick-Play Spell Card NaN NaN NaN NaN NaN NaN ... NaN NaN NaN (Effect, Ignition-like Effect) NaN NaN NaN Unlimited Unlimited Thu Mar 12 22:40:14 2020
3 "A" Cell Scatter Burst 73262676 Spell Card Quick-Play Spell Card NaN NaN NaN NaN NaN NaN ... NaN NaN NaN (Effect,) NaN NaN NaN Unlimited Unlimited Sat Nov 6 13:58:32 2021
4 "Infernoble Arms - Durendal" 37478723 Spell Card Equip Spell Card NaN NaN NaN NaN NaN NaN ... NaN NaN NaN (Condition, Ignition-like Effect, Trigger Effect) (Noble Arms,) NaN NaN Unlimited Unlimited Sat Aug 20 13:52:48 2022
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
12073 Yosenju Shinchu L 65025250 Monster Card NaN Effect Monster NaN WIND Rock 4 0 ... 3 NaN NaN (Continuous Effect, Continuous-like Effect, Tr... (Yosenju,) NaN NaN Unlimited Unlimited Sun Aug 14 11:04:00 2022
12074 Yosenju Shinchu R 91420254 Monster Card NaN Effect Monster NaN WIND Rock 4 0 ... 5 NaN NaN (Continuous Effect, Ignition-like Effect, Trig... (Yosenju,) NaN NaN Unlimited Unlimited Sat Aug 13 12:21:48 2022
12075 Yosenju Tsujik 25244515 Monster Card NaN Effect Monster NaN WIND Beast-Warrior 4 1000 ... NaN NaN NaN (Condition, Ignition Effect, Quick Effect, Tri... (Yosenju,) NaN NaN Unlimited Unlimited Sun Dec 20 18:15:02 2020
12076 ZW - Eagle Claw 29353756 Monster Card NaN Effect Monster NaN WIND Winged Beast 5 2000 ... NaN NaN NaN (Continuous-like Effect, Ignition Effect, Uncl... (ZW -, Zexal) NaN NaN Unlimited Unlimited Thu Jul 8 13:48:07 2021
12077 ZW - Tornado Bringer 81471108 Monster Card NaN Effect Monster NaN WIND Dragon 5 1300 ... NaN NaN NaN (Continuous-like Effect, Ignition Effect, Uncl... (ZW -, Zexal) NaN NaN Unlimited Unlimited Sun Aug 14 11:04:24 2022

12078 rows × 21 columns

Card types¶

formatted_full_df.groupby('Card type').nunique()
Name Password Property Primary type Secondary type Attribute Monster type Level/Rank ATK DEF Pendulum Scale Link Link Arrows Effect type Archseries Artwork Errata TCG status OCG status Modification date
Card type
Monster Card 7922 7817 0 8 6 7 25 15 82 77 13 6 61 222 984 3 3 7 7 7883
Spell Card 2350 2331 6 0 0 0 0 0 0 0 0 0 0 114 393 3 3 6 6 2340
Trap Card 1796 1779 3 0 0 0 0 0 0 0 0 0 0 95 323 3 3 6 6 1790
card_type_colors = [card_colors[i] for i in formatted_full_df['Card type'].value_counts().index]
formatted_full_df['Card type'].value_counts().plot.bar(figsize = (18,6), grid = True, rot=0, color = card_type_colors)
plt.show()

Monsters¶

Attributes¶

print('Total number of attributes:', formatted_monster_df['Attribute'].nunique())
Total number of attributes: 7
formatted_monster_df.drop(columns=['Card type']).groupby('Attribute').nunique()
Name Password Primary type Secondary type Monster type Level/Rank ATK DEF Pendulum Scale Link Link Arrows Effect type Archseries Artwork Errata TCG status OCG status Modification date
Attribute
DARK 2201 2173 7 6 23 14 70 63 12 6 39 153 447 3 3 7 7 2198
DIVINE 6 0 1 0 2 2 3 3 0 0 0 6 3 1 3 2 2 9
EARTH 1855 1840 7 6 23 12 71 59 11 4 29 124 325 3 3 5 6 1851
FIRE 662 657 8 6 22 12 43 40 8 4 22 85 184 3 3 3 6 660
LIGHT 1613 1575 7 6 23 14 58 50 10 5 30 131 381 3 3 7 6 1605
WATER 827 820 7 6 22 11 56 41 9 4 16 92 203 3 3 6 6 827
WIND 758 752 7 6 23 12 46 38 11 4 14 104 211 3 3 5 6 754
attribute_colors = [card_colors[i] for i in formatted_full_df['Attribute'].value_counts().index]
formatted_monster_df['Attribute'].value_counts().plot.bar(figsize = (18,6), grid = True, rot=0, color = attribute_colors)
plt.show()

Primary types¶

print('Total number of primary types:', formatted_monster_df['Primary type'].nunique())
Total number of primary types: 8
formatted_monster_df.drop(columns=['Card type']).groupby('Primary type').nunique()
Name Password Secondary type Attribute Monster type Level/Rank ATK DEF Pendulum Scale Link Link Arrows Effect type Archseries Artwork Errata TCG status OCG status Modification date
Primary type
Effect Monster 5386 5345 6 7 25 12 73 66 13 0 0 203 769 3 3 5 6 5360
Fusion Monster 420 419 1 6 23 12 48 46 3 0 0 66 140 3 3 4 4 418
Link Monster 364 358 0 6 23 0 38 0 0 6 61 51 138 3 2 5 4 364
Monster Token 1 0 0 1 1 1 1 1 0 0 0 0 1 0 0 0 1 1
Normal Monster 745 701 1 6 23 10 59 49 10 0 0 6 129 3 3 4 4 746
Ritual Monster 118 117 3 6 15 12 33 26 1 0 0 33 37 2 3 2 2 118
Synchro Monster 404 400 1 6 23 13 40 38 4 0 0 55 154 2 3 4 5 404
Xyz Monster 488 477 0 6 23 14 51 42 4 0 0 68 190 3 2 4 5 486

Has effect discrimination¶

has_effect = formatted_monster_df['Primary type'].where(formatted_monster_df['Effect type'].notna()).value_counts().rename('Effect')
no_effect = formatted_monster_df['Primary type'].where(formatted_monster_df['Effect type'].isna()).value_counts().rename('No Effect')
effect = pd.concat([has_effect,no_effect], axis=1)
effect
Effect No Effect
Effect Monster 5385.0 1
Xyz Monster 486.0 2
Synchro Monster 401.0 3
Link Monster 359.0 5
Fusion Monster 358.0 62
Ritual Monster 102.0 16
Normal Monster 34.0 712
Monster Token NaN 1
monster_type_colors = {'No Effect': card_colors['Normal Monster'], 'Effect': [card_colors[i] for i in effect.index]}
effect.plot.bar(figsize = (18,6), stacked = True, grid = True, rot=0,  legend=True, color = monster_type_colors)
plt.show()

Normal monster can have effect if it is pendulum

Is pendulum discrimination¶

not_pendulum = formatted_monster_df['Primary type'].where(formatted_monster_df['Pendulum Scale'].isna()).value_counts().rename('Not Pendulum')
is_pendulum = formatted_monster_df['Primary type'].where(formatted_monster_df['Pendulum Scale'].notna()).value_counts().rename('Pendulum')
pendulum = pd.concat([not_pendulum,is_pendulum], axis=1)
pendulum
Not Pendulum Pendulum
Effect Monster 5125 261.0
Normal Monster 708 38.0
Xyz Monster 481 7.0
Fusion Monster 411 9.0
Synchro Monster 399 5.0
Link Monster 364 NaN
Ritual Monster 117 1.0
Monster Token 1 NaN
monster_type_colors_b = {'Pendulum': card_colors['Pendulum Monster'], 'Not Pendulum': [card_colors[i] for i in pendulum.index]}
pendulum.plot.bar(figsize = (18,6), stacked = True, grid = True, rot=0, color = monster_type_colors_b, legend=True)
plt.show()

By attribute¶

primmary_crosstab = pd.crosstab(formatted_full_df['Primary type'],formatted_full_df['Attribute'])
primmary_crosstab
Attribute DARK DIVINE EARTH FIRE LIGHT WATER WIND
Primary type
Effect Monster 1481 6 1290 448 1089 547 525
Fusion Monster 144 0 79 34 96 34 33
Link Monster 117 0 74 33 86 29 25
Monster Token 0 0 0 1 0 0 0
Normal Monster 186 0 250 52 82 109 67
Ritual Monster 35 0 17 7 33 20 6
Synchro Monster 107 0 67 50 74 33 73
Xyz Monster 134 0 80 37 153 55 29
plt.figure(figsize = (16,10))
sns.heatmap(primmary_crosstab.T, annot=True, fmt="g", cmap='viridis', square=True, norm=LogNorm())
plt.show()

Secondary types¶

print('Total number of secondary types:', formatted_monster_df['Secondary type'].nunique())
Total number of secondary types: 6
formatted_monster_df.drop(columns=['Card type', 'Link', 'Link Arrows']).groupby('Secondary type').nunique()
Name Password Primary type Attribute Monster type Level/Rank ATK DEF Pendulum Scale Effect type Archseries Artwork Errata TCG status OCG status Modification date
Secondary type
Flip monster 183 182 2 6 19 12 38 33 1 20 45 2 3 3 4 183
Gemini monster 45 45 1 6 18 8 17 19 0 6 13 0 3 1 1 45
Spirit monster 37 37 2 6 13 9 22 20 2 7 4 1 1 2 2 37
Toon monster 17 17 1 6 7 5 12 15 0 8 13 1 2 1 2 17
Tuner monster 464 461 5 6 23 9 32 32 7 57 131 3 3 3 5 463
Union monster 37 37 1 6 9 8 17 14 0 6 9 1 2 1 1 37
secondary_type_colors = card_colors['Effect Monster']
formatted_monster_df['Secondary type'].value_counts().plot.bar(figsize = (18,6), stacked = True, grid = True, rot=0, color = secondary_type_colors, legend=True)
plt.show()

By attribute¶

secondary_crosstab = pd.crosstab(formatted_full_df['Secondary type'],formatted_full_df['Attribute'])
secondary_crosstab
Attribute DARK EARTH FIRE LIGHT WATER WIND
Secondary type
Flip monster 51 61 10 31 13 17
Gemini monster 11 8 8 6 8 4
Spirit monster 5 6 6 4 6 10
Toon monster 7 5 1 2 1 1
Tuner monster 119 91 42 94 50 68
Union monster 6 9 3 12 4 3
plt.figure(figsize = (8,6))
sns.heatmap(secondary_crosstab, annot=True, fmt="g", cmap='viridis', square=True)
plt.show()

By secondary type¶

secondary_crosstab_b = pd.crosstab(formatted_full_df['Primary type'],formatted_full_df['Secondary type'], margins = True)
secondary_crosstab_b
Secondary type Flip monster Gemini monster Spirit monster Toon monster Tuner monster Union monster All
Primary type
Effect Monster 182 45 35 17 418 37 734
Fusion Monster 0 0 0 0 3 0 3
Normal Monster 0 0 0 0 12 0 12
Ritual Monster 1 0 2 0 1 0 4
Synchro Monster 0 0 0 0 30 0 30
All 183 45 37 17 464 37 783
plt.figure(figsize = (10,7))
sns.heatmap(secondary_crosstab_b, annot=True, fmt="g", cmap='viridis', square=True, norm=LogNorm())
plt.show()

Monster types¶

print('Total number of monster types:', formatted_monster_df['Monster type'].nunique())
Total number of monster types: 25
formatted_monster_df.drop(columns=['Card type']).groupby('Monster type').nunique()
Name Password Primary type Secondary type Attribute Level/Rank ATK DEF Pendulum Scale Link Link Arrows Effect type Archseries Artwork Errata TCG status OCG status Modification date
Monster type
Aqua 254 252 7 6 6 10 50 33 3 2 3 51 64 2 3 3 3 254
Beast 376 368 7 4 6 10 48 38 7 2 7 59 84 3 3 4 6 377
Beast-Warrior 236 232 7 3 6 10 36 29 6 3 7 57 47 3 3 4 5 235
Creator God 1 0 1 0 1 1 1 1 0 0 0 1 1 0 0 0 1 1
Cyberse 246 244 7 1 6 11 30 29 1 6 38 45 34 2 2 3 4 246
Dinosaur 121 120 6 1 6 10 35 30 4 2 3 35 24 1 2 3 3 121
Divine-Beast 5 0 1 0 1 1 3 3 0 0 0 5 2 1 3 2 2 8
Dragon 654 648 7 6 6 13 52 48 9 5 19 109 184 2 3 6 6 651
Fairy 508 497 7 5 6 12 43 38 8 4 12 79 109 3 3 6 6 505
Fiend 759 746 7 6 6 13 60 45 12 5 14 106 147 3 3 6 5 758
Fish 122 121 7 2 5 10 34 28 1 1 1 30 21 2 2 2 3 122
Insect 237 236 7 3 6 12 44 33 2 3 6 55 39 2 2 2 3 237
Machine 912 900 7 5 6 12 62 55 9 4 22 111 166 3 3 5 7 907
Plant 230 228 6 4 6 9 37 30 5 4 9 38 38 2 2 3 4 230
Psychic 177 173 6 2 6 11 35 31 5 2 3 42 42 1 2 4 5 177
Pyro 121 120 7 5 5 11 34 29 0 1 1 36 33 1 3 1 3 121
Reptile 171 170 6 3 6 11 37 30 3 2 3 46 35 0 2 4 3 171
Rock 246 244 7 4 6 11 43 39 4 3 4 59 72 1 3 5 5 245
Sea Serpent 82 82 6 3 6 10 28 26 1 2 2 32 28 2 3 2 2 82
Spellcaster 673 662 7 5 6 12 49 40 10 5 12 100 146 3 3 5 6 671
Thunder 128 125 6 4 6 10 35 29 1 2 4 37 33 1 2 3 4 128
Warrior 1023 1015 7 6 6 13 60 41 6 3 15 92 215 3 3 6 7 1021
Winged Beast 312 309 7 5 6 10 39 29 4 4 6 61 65 2 3 4 5 312
Wyrm 86 85 6 1 6 11 26 24 3 4 6 32 20 1 1 4 3 86
Zombie 242 240 7 5 6 12 38 37 1 3 5 51 35 2 3 1 2 241
monster_type_colors = card_colors['Monster Card']
formatted_monster_df['Monster type'].value_counts().plot.bar(figsize = (18,6), grid = True, rot=45, color = monster_type_colors)
plt.show()

By Attribute¶

monster_crosstab = pd.crosstab(formatted_full_df['Monster type'],formatted_full_df['Attribute'], dropna=False)
monster_crosstab
Attribute DARK DIVINE EARTH FIRE LIGHT WATER WIND
Monster type
Aqua 9 0 6 10 4 219 6
Beast 37 0 213 16 72 14 25
Beast-Warrior 37 0 82 53 33 16 15
Creator God 0 1 0 0 0 0 0
Cyberse 63 0 36 44 63 28 12
Dinosaur 11 0 59 32 5 8 6
Divine-Beast 0 8 0 0 0 0 0
Dragon 251 0 47 48 167 28 113
Fairy 55 0 61 17 324 26 25
Fiend 573 0 33 46 70 23 16
Fish 2 0 2 0 1 115 2
Insect 37 0 127 6 20 4 43
Machine 223 0 308 50 167 48 116
Plant 42 0 118 11 22 24 13
Psychic 23 0 37 17 45 13 42
Pyro 2 0 6 106 4 0 3
Reptile 39 0 34 15 45 34 4
Rock 16 0 198 5 15 5 7
Sea Serpent 3 0 1 1 2 71 4
Spellcaster 281 0 53 28 187 63 62
Thunder 13 0 10 5 77 4 19
Warrior 202 0 363 101 245 53 60
Winged Beast 109 0 7 16 15 12 153
Wyrm 15 0 18 10 23 12 8
Zombie 161 0 38 25 7 7 4
plt.figure(figsize = (20,5))
sns.heatmap(monster_crosstab.T, annot=True, fmt="g", cmap='viridis', square=True)
plt.show()

By primary type¶

monster_crosstab_b = pd.crosstab(formatted_full_df['Monster type'],formatted_full_df['Primary type'], dropna=False)
monster_crosstab_b
Primary type Effect Monster Fusion Monster Link Monster Monster Token Normal Monster Ritual Monster Synchro Monster Xyz Monster
Monster type
Aqua 153 11 3 0 59 8 3 17
Beast 271 17 9 0 54 1 14 11
Beast-Warrior 162 11 9 0 21 2 8 23
Creator God 1 0 0 0 0 0 0 0
Cyberse 122 4 93 0 7 6 5 9
Dinosaur 86 7 3 0 18 0 4 3
Divine-Beast 5 0 0 0 0 0 0 0
Dragon 345 62 33 0 46 15 93 60
Fairy 362 20 24 0 36 17 17 32
Fiend 532 46 27 0 79 15 22 40
Fish 88 5 1 0 17 1 7 3
Insect 175 2 9 0 29 1 7 14
Machine 633 46 38 0 67 4 60 64
Plant 161 6 15 0 25 0 7 16
Psychic 120 11 5 0 9 0 19 13
Pyro 84 8 1 1 18 0 5 4
Reptile 140 1 3 0 19 0 5 3
Rock 168 18 4 0 28 7 5 16
Sea Serpent 55 2 2 0 8 0 5 10
Spellcaster 510 25 26 0 55 17 16 25
Thunder 97 8 5 0 11 0 5 2
Warrior 672 93 29 0 80 14 54 82
Winged Beast 227 8 9 0 27 4 15 22
Wyrm 54 2 9 0 3 0 10 8
Zombie 163 7 7 0 30 6 18 11
plt.figure(figsize = (20,5))
sns.heatmap(monster_crosstab_b.T, annot=True, fmt="g", cmap='viridis', square=True, norm = LogNorm())
plt.show()

By secondary type¶

monster_crosstab_c = pd.crosstab(formatted_full_df['Monster type'],formatted_full_df['Secondary type'], dropna=False)
monster_crosstab_c
Secondary type Flip monster Gemini monster Spirit monster Toon monster Tuner monster Union monster
Monster type
Aqua 4 4 1 1 10 3
Beast 15 1 2 0 22 0
Beast-Warrior 1 0 1 0 9 0
Cyberse 0 0 0 0 6 0
Dinosaur 0 0 0 0 7 0
Dragon 1 6 1 3 42 4
Fairy 8 2 7 0 20 5
Fiend 27 4 2 1 41 1
Fish 0 1 0 0 7 0
Insect 20 2 0 0 11 0
Machine 10 1 0 4 80 18
Plant 4 1 0 0 20 1
Psychic 3 0 0 0 23 0
Pyro 4 2 2 0 8 1
Reptile 18 1 0 0 7 0
Rock 11 1 2 0 3 0
Sea Serpent 1 1 0 0 9 0
Spellcaster 33 3 4 4 39 0
Thunder 3 1 1 0 8 0
Warrior 11 9 5 3 30 3
Winged Beast 5 2 7 1 30 0
Wyrm 0 0 0 0 10 0
Zombie 4 3 2 0 22 1
plt.figure(figsize = (20,5))
sns.heatmap(monster_crosstab_c.T, annot=True, fmt="g", cmap='viridis', square=True, norm = LogNorm())
plt.show()

Effect type¶

print('Total number of effect types:', formatted_monster_df['Effect type'].explode().nunique())
Total number of effect types: 14
formatted_monster_df[formatted_monster_df['Effect type'].notna()].drop(columns=['Card type']).explode('Effect type').groupby('Effect type').nunique()
Name Password Primary type Secondary type Attribute Monster type Level/Rank ATK DEF Pendulum Scale Link Link Arrows Archseries Artwork Errata TCG status OCG status Modification date
Effect type
Activation condition 1 1 1 0 1 1 1 1 1 1 0 0 1 0 0 1 1 1
Condition 3008 2957 7 6 7 25 14 63 63 13 5 53 634 3 3 5 6 2996
Continuous Effect 2130 2116 6 5 7 24 14 59 52 12 6 48 554 3 3 4 4 2127
Continuous-like Effect 233 233 6 3 6 21 11 42 36 13 1 2 72 2 3 3 3 233
Flip effect 169 168 1 1 6 19 12 38 33 1 0 0 43 2 3 3 4 169
Ignition Effect 2572 2554 6 6 7 24 13 66 61 12 5 42 632 3 3 5 6 2565
Ignition-like Effect 214 208 6 2 6 20 12 35 32 13 1 1 73 1 3 3 4 214
Lingering effect 16 16 2 1 6 11 7 11 13 0 2 2 9 0 0 2 2 16
Maintenance cost 44 44 3 0 6 12 8 21 18 2 1 1 8 0 1 1 1 44
Quick Effect 998 992 6 4 6 23 13 50 47 8 5 28 387 3 3 5 4 995
Quick-like Effect 4 4 1 0 1 1 1 3 2 0 0 0 1 0 0 1 1 4
Summoning condition 905 865 6 4 7 25 13 52 51 8 5 6 313 3 3 6 5 901
Trigger Effect 4262 4241 7 6 7 24 14 66 62 13 5 49 756 3 3 4 6 4242
Unclassified effect 807 796 6 5 7 25 13 49 45 9 5 12 272 3 3 3 4 804
monster_effect_colors = card_colors['Effect Monster']
formatted_monster_df['Effect type'].explode('Effect type').value_counts().plot.bar(figsize = (18,6), grid = True, color = monster_effect_colors)
plt.show()

ATK¶

print('Total number of ATK values:', formatted_monster_df['ATK'].nunique())
Total number of ATK values: 82
formatted_monster_df.drop(columns=['Card type']).groupby('ATK').nunique().sort_index(key=lambda x: pd.to_numeric(x, errors = 'coerce'))
Name Password Primary type Secondary type Attribute Monster type Level/Rank DEF Pendulum Scale Link Link Arrows Effect type Archseries Artwork Errata TCG status OCG status Modification date
ATK
0 610 584 8 5 6 23 13 35 9 5 15 92 233 3 3 5 6 609
50 2 2 1 0 2 2 1 2 0 0 0 2 2 0 0 1 1 2
100 217 216 5 3 6 20 11 27 8 2 2 48 107 2 3 2 3 217
150 1 1 1 0 1 1 1 1 0 0 0 0 0 0 0 1 1 1
200 118 117 6 5 6 20 7 21 4 1 2 34 67 2 3 2 4 118
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
4500 12 12 3 0 3 6 4 4 0 0 0 10 9 1 1 1 1 12
4600 2 2 1 0 2 1 1 1 0 0 0 2 1 0 0 1 1 2
5000 9 9 5 0 3 4 2 4 0 1 1 8 6 1 1 1 1 9
? 83 75 6 1 7 20 15 8 2 1 1 34 36 2 3 4 4 84
X000 1 0 0 0 1 1 1 1 0 0 0 0 1 0 0 1 1 1

82 rows × 18 columns

atk_colors = card_colors['Monster Card']
formatted_monster_df['DEF'].value_counts().sort_index(key=lambda x: pd.to_numeric(x, errors = 'coerce')).plot.bar(figsize = (18,6), grid = True, color = atk_colors)
plt.show()

DEF¶

print('Total number of DEF values:', formatted_monster_df['DEF'].nunique())
Total number of DEF values: 77
formatted_monster_df.drop(columns=['Card type']).groupby('DEF').nunique().sort_index(key=lambda x: pd.to_numeric(x, errors = 'coerce'))
Name Password Primary type Secondary type Attribute Monster type Level/Rank ATK Pendulum Scale Link Link Arrows Effect type Archseries Artwork Errata TCG status OCG status Modification date
DEF
0 764 737 7 6 6 23 14 45 10 0 0 104 258 3 3 5 5 761
50 1 1 1 0 1 1 1 1 0 0 0 1 1 0 0 1 1 1
100 208 207 5 4 6 19 10 24 8 0 0 46 95 2 3 3 3 207
200 248 246 5 5 6 23 10 31 5 0 0 47 108 3 3 3 5 248
250 8 8 2 1 4 5 2 4 0 0 0 5 3 0 1 1 1 8
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
4500 2 2 2 0 2 2 1 1 0 0 0 2 1 0 0 1 1 2
4800 1 1 1 0 1 1 1 1 0 0 0 1 1 0 0 1 1 1
5000 5 5 2 0 3 3 2 2 0 0 0 4 3 1 1 1 1 5
? 56 49 5 1 7 17 14 2 1 0 0 25 25 2 3 4 4 57
X000 1 0 0 0 1 1 1 1 0 0 0 0 1 0 0 1 1 1

77 rows × 18 columns

def_colors = card_colors['Monster Card']
formatted_monster_df['DEF'].value_counts().sort_index(key=lambda x: pd.to_numeric(x, errors = 'coerce')).plot.bar(figsize = (18,6), grid = True, color = def_colors)
plt.show()

Level/Rank¶

formatted_monster_df.drop(columns=['Card type', 'Link', 'Link Arrows']).groupby('Level/Rank').nunique().sort_index(key=lambda x: pd.to_numeric(x, errors = 'coerce'))
Name Password Primary type Secondary type Attribute Monster type ATK DEF Pendulum Scale Effect type Archseries Artwork Errata TCG status OCG status Modification date
Level/Rank
0 6 6 2 0 2 2 3 3 0 5 3 0 0 2 2 6
1 627 601 7 5 6 23 22 29 10 80 227 3 3 4 5 625
2 671 662 6 5 6 23 29 30 7 73 213 3 3 4 6 670
3 1142 1136 6 5 6 23 41 36 9 92 290 3 3 4 7 1142
4 2323 2312 6 6 6 23 54 47 9 134 504 3 3 4 7 2316
5 591 591 6 6 6 23 46 38 8 83 233 3 3 3 3 591
6 601 597 6 6 6 23 38 38 9 92 233 3 3 5 6 602
7 465 457 6 6 6 23 37 35 9 100 224 3 3 4 6 466
8 665 648 6 5 6 23 42 41 8 110 298 3 3 4 5 666
9 141 138 5 2 6 21 30 27 1 55 85 1 3 4 4 141
10 244 232 5 2 7 22 32 33 6 76 146 2 3 3 4 247
11 31 30 6 2 6 13 16 17 1 22 23 0 1 3 2 31
12 49 48 5 1 6 12 12 16 2 31 36 1 2 2 2 49
13 1 1 1 0 1 1 1 1 0 1 1 0 0 1 1 1
? 1 0 1 0 1 1 1 1 0 0 0 0 0 0 1 1
stars_colors = card_colors['Level']
formatted_monster_df['Level/Rank'].value_counts().sort_index(key=lambda x: pd.to_numeric(x, errors = 'coerce')).plot.bar(figsize = (18,6), grid = True, rot=0, color= stars_colors)
plt.show()

ATK statistics¶

formatted_monster_df[['Level/Rank','ATK']].apply(pd.to_numeric, errors = 'coerce').dropna().astype(int).groupby('Level/Rank').describe()
ATK
count mean std min 25% 50% 75% max
Level/Rank
0 5.0 600.000000 1341.640786 0.0 0.0 0.0 0.0 3000.0
1 617.0 239.789303 352.151718 0.0 0.0 100.0 300.0 2500.0
2 669.0 582.585949 409.056579 0.0 300.0 500.0 800.0 2400.0
3 1139.0 958.955224 485.391745 0.0 600.0 1000.0 1300.0 3000.0
4 2311.0 1418.576374 540.051712 0.0 1200.0 1500.0 1800.0 3000.0
5 588.0 1765.765306 638.460344 0.0 1500.0 1900.0 2200.0 4000.0
6 598.0 2012.792642 615.312202 0.0 1900.0 2200.0 2400.0 4000.0
7 461.0 2287.093275 619.117017 0.0 2200.0 2500.0 2600.0 3300.0
8 657.0 2548.630137 708.279398 0.0 2500.0 2800.0 3000.0 4500.0
9 138.0 2593.115942 844.846810 0.0 2500.0 2800.0 3000.0 4500.0
10 224.0 2824.330357 1219.607927 0.0 2800.0 3000.0 3500.0 5000.0
11 30.0 2990.000000 1093.113238 0.0 3000.0 3350.0 3500.0 4000.0
12 45.0 3355.555556 1429.964328 0.0 3000.0 4000.0 4000.0 5000.0

DEF statistics¶

formatted_monster_df[['Level/Rank','DEF']].apply(pd.to_numeric, errors = 'coerce').dropna().astype(int).groupby('Level/Rank').describe()
DEF
count mean std min 25% 50% 75% max
Level/Rank
0 5.0 400.000000 894.427191 0.0 0.0 0.0 0.0 2000.0
1 619.0 337.883683 519.434793 0.0 0.0 100.0 400.0 2500.0
2 670.0 660.000000 555.322123 0.0 200.0 500.0 900.0 2400.0
3 1139.0 954.784899 571.624287 0.0 600.0 900.0 1300.0 3000.0
4 2313.0 1169.835711 606.318852 0.0 800.0 1200.0 1600.0 3000.0
5 589.0 1421.731749 673.303655 0.0 1000.0 1500.0 1900.0 3000.0
6 598.0 1560.418060 708.831576 0.0 1200.0 1700.0 2000.0 3000.0
7 463.0 1884.017279 653.937008 0.0 1600.0 2000.0 2300.0 3300.0
8 664.0 1976.204819 845.673967 0.0 1600.0 2100.0 2500.0 4000.0
9 138.0 2309.057971 793.914709 0.0 2000.0 2500.0 2975.0 3700.0
10 233.0 2230.686695 1281.773909 0.0 1900.0 2500.0 3000.0 5000.0
11 30.0 2661.666667 1169.415071 0.0 2125.0 3000.0 3400.0 4000.0
12 46.0 2852.173913 1672.089728 0.0 2000.0 3350.0 4000.0 5000.0

Pendulum scale¶

formatted_monster_df.drop(columns=['Card type', 'Link', 'Link Arrows']).groupby('Pendulum Scale').nunique().sort_index(key=lambda x: pd.to_numeric(x, errors = 'coerce'))
Name Password Primary type Secondary type Attribute Monster type Level/Rank ATK DEF Effect type Archseries Artwork Errata TCG status OCG status Modification date
Pendulum Scale
0 10 10 2 1 5 7 6 5 5 8 8 1 0 1 1 10
1 67 64 5 2 6 10 11 28 26 37 38 0 1 3 4 67
2 36 36 2 1 6 11 6 17 22 21 15 0 2 3 2 36
3 36 36 2 1 6 15 8 22 15 23 17 0 0 1 1 36
4 32 32 5 0 5 8 8 18 16 25 16 1 1 1 1 32
5 34 34 2 1 6 12 7 23 21 20 16 0 1 3 3 34
6 15 15 1 1 4 7 6 11 11 11 9 0 0 1 1 15
7 27 27 2 1 6 14 6 19 17 14 16 0 2 1 1 27
8 39 39 5 1 6 9 8 19 18 23 21 0 0 1 2 39
9 8 8 2 1 3 3 5 3 2 5 3 0 0 1 1 8
10 14 11 5 0 6 6 5 6 8 11 8 0 0 2 2 14
12 2 2 1 0 1 2 2 2 2 2 2 0 0 1 1 2
13 1 1 1 0 1 1 1 1 1 1 1 0 0 1 1 1
scales_colors = card_colors['Pendulum Monster']
formatted_monster_df['Pendulum Scale'].value_counts().sort_index(key=lambda x: pd.to_numeric(x, errors = 'coerce')).plot.bar(figsize = (18,6), grid = True, rot=0, color = scales_colors)
plt.show()

ATK statistics¶

formatted_monster_df[['Pendulum Scale','ATK']].apply(pd.to_numeric, errors = 'coerce').dropna().astype(int).groupby('Pendulum Scale').describe()
ATK
count mean std min 25% 50% 75% max
Pendulum Scale
0 10.0 1390.000000 1317.784336 0.0 0.0 1450.0 2500.0 3000.0
1 66.0 1751.515152 1053.381723 0.0 1000.0 1800.0 2500.0 4000.0
2 36.0 1423.611111 688.734462 100.0 800.0 1500.0 2000.0 2500.0
3 36.0 1437.500000 845.354955 0.0 600.0 1725.0 2025.0 2600.0
4 32.0 1787.500000 1011.785391 0.0 1100.0 2000.0 2550.0 3000.0
5 34.0 1339.705882 808.831875 0.0 850.0 1325.0 1800.0 3450.0
6 15.0 1320.000000 707.308783 100.0 950.0 1500.0 1800.0 2400.0
7 27.0 1279.629630 787.920737 0.0 700.0 1400.0 1750.0 3000.0
8 39.0 1225.641026 968.644726 0.0 300.0 1200.0 2000.0 3300.0
9 8.0 2150.000000 730.948503 1000.0 2050.0 2400.0 2500.0 2800.0
10 14.0 1678.571429 1376.829452 0.0 125.0 2500.0 2875.0 3000.0
12 1.0 100.000000 NaN 100.0 100.0 100.0 100.0 100.0
13 1.0 0.000000 NaN 0.0 0.0 0.0 0.0 0.0

DEF statistics¶

formatted_monster_df[['Pendulum Scale','DEF']].apply(pd.to_numeric, errors = 'coerce').dropna().astype(int).groupby('Pendulum Scale').describe()
DEF
count mean std min 25% 50% 75% max
Pendulum Scale
0 10.0 1200.000000 1273.664878 0.0 0.0 750.0 2500.0 3000.0
1 67.0 1571.641791 940.310389 0.0 950.0 1700.0 2350.0 4000.0
2 36.0 1338.888889 728.316171 0.0 875.0 1200.0 1825.0 2700.0
3 36.0 1165.277778 788.834533 0.0 575.0 1200.0 1800.0 3000.0
4 32.0 1534.375000 830.316448 0.0 1000.0 1600.0 2075.0 2800.0
5 34.0 1136.764706 822.625953 0.0 550.0 1000.0 1575.0 3000.0
6 15.0 1226.666667 711.604492 400.0 600.0 1100.0 1700.0 2600.0
7 27.0 1312.962963 830.383669 0.0 700.0 1300.0 2000.0 2700.0
8 39.0 1015.384615 789.916205 0.0 350.0 1000.0 1700.0 2700.0
9 8.0 1225.000000 636.396103 1000.0 1000.0 1000.0 1000.0 2800.0
10 14.0 1850.000000 1124.380171 0.0 750.0 2500.0 2575.0 3000.0
12 1.0 100.000000 NaN 100.0 100.0 100.0 100.0 100.0
13 1.0 0.000000 NaN 0.0 0.0 0.0 0.0 0.0

Level/Rank statistics¶

formatted_monster_df[['Pendulum Scale','Level/Rank']].apply(pd.to_numeric, errors = 'coerce').dropna().astype(int).groupby('Pendulum Scale').describe()
Level/Rank
count mean std min 25% 50% 75% max
Pendulum Scale
0 10.0 6.100000 3.348300 1.0 3.75 7.0 8.00 10.0
1 67.0 5.955224 2.427324 1.0 4.00 6.0 8.00 12.0
2 36.0 4.416667 1.380993 1.0 3.75 4.0 5.00 7.0
3 36.0 4.444444 1.731134 1.0 4.00 4.0 5.00 10.0
4 32.0 5.562500 2.154328 1.0 4.00 6.0 7.00 8.0
5 34.0 4.176471 1.961301 1.0 3.00 4.0 4.00 11.0
6 15.0 3.933333 1.579632 1.0 3.00 4.0 4.50 8.0
7 27.0 4.185185 1.641693 2.0 3.00 4.0 5.00 10.0
8 39.0 3.923077 2.355113 1.0 2.00 4.0 6.00 10.0
9 8.0 5.625000 1.302470 4.0 5.00 5.0 6.25 8.0
10 14.0 6.714286 2.812843 1.0 7.00 7.0 7.75 10.0
12 2.0 6.500000 7.778175 1.0 3.75 6.5 9.25 12.0
13 1.0 7.000000 NaN 7.0 7.00 7.0 7.00 7.0

Link¶

formatted_monster_df.drop(columns=['Card type', 'Primary type', 'Secondary type','Level/Rank','DEF','Pendulum Scale']).groupby('Link').nunique().sort_index(key=lambda x: pd.to_numeric(x, errors = 'coerce'))
Name Password Attribute Monster type ATK Link Arrows Effect type Archseries Artwork Errata TCG status OCG status Modification date
Link
1 47 47 6 11 10 8 17 26 1 0 3 3 47
2 183 183 6 23 23 19 31 101 1 2 4 3 183
3 81 81 6 16 17 17 25 46 2 1 2 2 81
4 44 41 6 16 12 13 21 24 2 0 3 4 44
5 8 5 2 5 4 3 5 4 0 0 2 2 8
6 1 1 1 1 1 1 1 1 0 0 1 1 1
link_colors = card_colors['Link Monster']
formatted_monster_df['Link'].value_counts().sort_index(key=lambda x: pd.to_numeric(x, errors = 'coerce')).plot.bar(figsize = (18,6), grid = True, rot=0, color = link_colors)
plt.show()

ATK statistics¶

formatted_monster_df[['Link','ATK']].apply(pd.to_numeric, errors = 'coerce').dropna().astype(int).groupby('Link').describe()
ATK
count mean std min 25% 50% 75% max
Link
1 47.0 736.170213 482.937358 0.0 400.0 800.0 1000.0 1500.0
2 183.0 1399.726776 509.349328 0.0 1100.0 1500.0 1800.0 2300.0
3 81.0 2258.641975 659.487970 0.0 2200.0 2400.0 2500.0 4000.0
4 43.0 2660.465116 653.976676 0.0 2500.0 2800.0 3000.0 3300.0
5 8.0 3250.000000 755.928946 2500.0 3000.0 3000.0 3125.0 5000.0
6 1.0 0.000000 NaN 0.0 0.0 0.0 0.0 0.0

Link Arrows¶

By combination¶

print('Total number of link arrow combinations:', formatted_monster_df['Link Arrows'].nunique())
Total number of link arrow combinations: 61
formatted_monster_df.drop(columns=['Card type', 'Primary type', 'Level/Rank', 'Pendulum Scale', 'Link', 'Secondary type', 'DEF']).groupby('Link Arrows').nunique()
Name Password Attribute Monster type ATK Effect type Archseries Artwork Errata TCG status OCG status Modification date
Link Arrows
(←,) 5 5 2 3 2 4 4 0 0 3 2 5
(←, ↑) 4 4 2 3 4 3 2 0 0 1 1 4
(←, →) 18 18 6 8 11 8 9 0 0 2 2 18
(←, →, ↑) 7 7 3 5 6 6 5 0 0 1 1 7
(↑,) 10 10 5 5 6 9 5 0 0 1 1 10
... ... ... ... ... ... ... ... ... ... ... ... ...
(↙, ↘, ←, ↖) 1 1 1 1 1 1 1 0 0 1 1 1
(↙, ↘, ↑) 22 22 6 11 11 11 15 1 1 2 2 22
(↙, ↘, →) 2 2 2 2 2 2 2 0 0 1 1 2
(↙, ↘, ↖) 2 2 2 2 2 2 0 0 0 1 1 2
(↙, ↘, ↖, ↗) 1 1 1 1 1 1 1 0 0 1 1 1

61 rows × 12 columns

arrows_colors = card_colors['Link Monster']
formatted_monster_df['Link Arrows'].value_counts().plot.bar(figsize = (18,6), logy=True, grid = True, color = arrows_colors)
plt.show()

By unique¶

formatted_monster_df[formatted_monster_df['Link Arrows'].notna()].drop(columns=['Card type', 'Primary type', 'Level/Rank', 'Pendulum Scale', 'Secondary type', 'DEF']).explode('Link Arrows').groupby('Link Arrows').nunique()
Name Password Attribute Monster type ATK Link Effect type Archseries Artwork Errata TCG status OCG status Modification date
Link Arrows
← 113 107 6 21 29 6 34 45 2 0 5 3 113
↑ 114 111 6 19 27 6 31 44 2 1 3 4 114
→ 99 93 6 19 27 6 29 40 2 0 3 4 99
↓ 156 150 6 20 31 6 41 68 3 0 4 4 156
↖ 10 10 5 5 9 4 6 5 1 0 1 2 10
↗ 15 15 5 7 10 5 7 7 0 0 1 2 15
↘ 184 181 6 22 32 6 35 102 3 2 4 4 184
↙ 187 184 6 22 33 6 37 103 3 2 4 4 187
arrows_colors_b = card_colors['Link Monster']
formatted_monster_df['Link Arrows'].explode('Link Arrows').value_counts().plot.bar(figsize = (18,6), grid = True, color = arrows_colors_b)
plt.show()

By link¶

arrow_per_link = formatted_monster_df[['Link Arrows','Link']].explode('Link Arrows').dropna()
arrow_crosstab = pd.crosstab(arrow_per_link['Link Arrows'],arrow_per_link['Link'])
arrow_crosstab
Link 1 2 3 4 5 6
Link Arrows
← 5 47 23 30 7 1
↑ 10 28 43 28 4 1
→ 2 33 24 31 8 1
↓ 18 59 41 32 5 1
↖ 1 2 5 2 0 0
↗ 3 5 3 3 1 0
↘ 3 94 53 25 8 1
↙ 5 98 51 25 7 1
plt.figure(figsize = (10,6))
sns.heatmap(arrow_crosstab.T, annot=True, fmt="g", cmap='viridis', square=True, norm=LogNorm())
plt.show()

Spell & Trap¶

Properties¶

print('Total number of properties:', formatted_st_df['Property'].nunique())
Total number of properties: 9
formatted_st_df.drop(columns=['Card type']).groupby('Property').nunique()
Name Password Effect type Archseries Artwork Errata TCG status OCG status Modification date
Property
Continuous Spell Card 415 412 53 157 3 3 6 5 413
Continuous Trap Card 487 479 63 160 2 3 5 2 487
Counter Trap Card 154 152 19 58 2 2 3 2 154
Equip Spell Card 262 262 37 74 1 3 2 2 262
Field Spell Card 271 266 35 144 2 3 5 5 272
Normal Spell Card 907 902 43 227 3 3 5 6 906
Normal Trap Card 1155 1148 48 238 3 2 5 6 1151
Quick-Play Spell Card 420 415 34 138 3 3 4 4 419
Ritual Spell Card 75 74 8 25 2 2 1 2 75
st_colors = [card_colors[i] for i in formatted_full_df[['Card type','Property']].value_counts().index.get_level_values(0)]
formatted_st_df['Property'].value_counts().plot.bar(figsize = (18,6), grid = True, rot=45, color = st_colors)
plt.show()

Effect type¶

print('Total number of effect types:', formatted_st_df['Effect type'].explode().nunique())
Total number of effect types: 14
formatted_st_df.explode('Effect type').groupby('Effect type').nunique()
Name Password Card type Property Archseries Artwork Errata TCG status OCG status Modification date
Effect type
Activation condition 832 825 2 8 171 3 3 4 5 831
Condition 1644 1621 2 9 368 3 3 6 5 1634
Continuous Effect 21 21 2 6 12 0 2 1 1 21
Continuous-like Effect 893 883 2 7 236 3 3 6 5 893
Cost 452 450 2 7 112 3 3 4 4 452
Effect 2899 2871 2 9 426 3 3 6 6 2885
Ignition Effect 2 2 2 2 2 0 0 1 1 2
Ignition-like Effect 428 425 1 6 179 1 2 5 5 427
Lingering effect 94 94 2 6 41 2 2 3 3 94
Maintenance cost 22 22 2 5 7 1 1 3 3 22
Quick Effect 9 9 2 3 4 0 0 1 1 9
Quick-like Effect 331 326 2 4 146 2 1 3 5 331
Trigger Effect 835 824 2 9 256 2 3 4 5 829
Unclassified effect 83 83 2 9 48 1 0 2 2 82

Spell & Trap discrimination¶

spell = formatted_spell_df['Effect type'].explode('Effect type').value_counts().rename('Spell Card')
trap = formatted_trap_df['Effect type'].explode('Effect type').value_counts().rename('Trap Card')
st_diff = pd.concat([spell, trap], axis = 1)
st_diff
Spell Card Trap Card
Effect 1508 1392.0
Condition 1116 529.0
Continuous-like Effect 614 280.0
Trigger Effect 560 275.0
Ignition-like Effect 428 NaN
Activation condition 244 588.0
Cost 241 211.0
Unclassified effect 63 20.0
Lingering effect 56 38.0
Maintenance cost 11 11.0
Continuous Effect 7 14.0
Quick Effect 4 5.0
Quick-like Effect 3 328.0
Ignition Effect 1 1.0
st_diff_colors = {'Spell Card': card_colors['Spell Card'], 'Trap Card': card_colors['Trap Card']}
st_diff.plot.bar(figsize = (18,6), stacked = True, grid = True, rot=45, color = st_diff_colors)
plt.show()

Archseries¶

exploded_archseries = formatted_full_df.explode('Archseries')
print('Total number of Archseries:', exploded_archseries['Archseries'].nunique())
Total number of Archseries: 710
exploded_archseries.groupby('Archseries').nunique()
Name Password Card type Property Primary type Secondary type Attribute Monster type Level/Rank ATK DEF Pendulum Scale Link Link Arrows Effect type Artwork Errata TCG status OCG status Modification date
Archseries
"C" 8 8 1 0 2 0 1 1 7 8 8 0 0 0 6 0 1 2 1 8
-Eyes Dragon 72 71 1 0 7 2 6 3 10 16 13 6 1 1 44 1 3 2 3 71
/Assault Mode 7 7 1 0 1 0 5 6 5 6 6 0 0 0 5 0 0 1 1 7
@Ignister 18 18 1 0 6 1 6 1 7 10 9 0 3 4 9 0 0 1 1 18
A-to-Z 16 16 1 0 3 1 1 1 4 13 12 0 0 0 5 2 3 1 2 16
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
sphinx 10 10 2 1 1 0 2 2 4 8 5 0 0 0 9 0 0 1 1 10
sprout 2 2 1 0 1 0 1 1 1 1 1 0 0 0 2 0 0 1 1 2
tellarknight 21 21 2 3 2 0 2 3 2 16 14 2 0 0 11 0 0 2 2 21
with Chain 4 4 1 1 0 0 0 0 0 0 0 0 0 0 4 1 0 1 1 4
with Eyes of Blue 8 8 2 2 1 1 1 1 1 3 4 0 0 0 6 0 1 1 1 8

710 rows × 20 columns

exploded_archseries['Archseries'].value_counts().plot.barh(figsize = (10,200), grid = True)
plt.show()

By card type¶

archseries_crosstab = pd.crosstab(exploded_archseries['Archseries'],exploded_archseries['Card type'], margins = True)
archseries_crosstab
Card type Monster Card Spell Card Trap Card All
Archseries
"C" 8 0 0 8
-Eyes Dragon 72 0 0 72
/Assault Mode 7 0 0 7
@Ignister 18 0 0 18
A-to-Z 16 0 0 16
... ... ... ... ...
sprout 2 0 0 2
tellarknight 17 4 0 21
with Chain 0 0 4 4
with Eyes of Blue 5 3 0 8
All 7245 1344 889 9478

711 rows × 4 columns

By primary type¶

archseries_crosstab_b = pd.crosstab(exploded_archseries['Archseries'],exploded_archseries['Primary type'], margins = True)
archseries_crosstab_b
Primary type Effect Monster Fusion Monster Link Monster Monster Token Normal Monster Ritual Monster Synchro Monster Xyz Monster All
Archseries
"C" 7 0 0 0 1 0 0 0 8
-Eyes Dragon 31 11 1 0 3 4 5 17 72
/Assault Mode 7 0 0 0 0 0 0 0 7
@Ignister 10 1 4 0 0 1 1 1 18
A-to-Z 6 8 0 0 2 0 0 0 16
... ... ... ... ... ... ... ... ... ...
sphinx 9 0 0 0 0 0 0 0 9
sprout 2 0 0 0 0 0 0 0 2
tellarknight 12 0 0 0 0 0 0 5 17
with Eyes of Blue 5 0 0 0 0 0 0 0 5
All 4653 529 331 1 244 119 433 931 7241

647 rows × 9 columns

By secondary type¶

archseries_crosstab_c = pd.crosstab(exploded_archseries['Archseries'],exploded_archseries['Secondary type'], margins = True)
archseries_crosstab_c
Secondary type Flip monster Gemini monster Spirit monster Toon monster Tuner monster Union monster All
Archseries
-Eyes Dragon 0 2 0 2 0 0 4
@Ignister 0 0 0 0 1 0 1
A-to-Z 0 0 0 0 0 6 6
Adamancipator 0 0 0 0 3 0 3
Alien 1 1 0 0 1 0 3
... ... ... ... ... ... ... ...
itsu 0 0 0 0 0 2 2
lswarm 2 0 0 0 0 0 2
roid 0 0 0 0 9 0 9
with Eyes of Blue 0 0 0 0 5 0 5
All 126 28 13 36 414 18 635

196 rows × 7 columns

By monster type¶

archseries_crosstab_d = pd.crosstab(exploded_archseries['Archseries'],exploded_archseries['Monster type'], margins = True)
archseries_crosstab_d
Monster type Aqua Beast Beast-Warrior Creator God Cyberse Dinosaur Divine-Beast Dragon Fairy Fiend ... Reptile Rock Sea Serpent Spellcaster Thunder Warrior Winged Beast Wyrm Zombie All
Archseries
"C" 0 0 0 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0 0 8
-Eyes Dragon 0 0 0 0 0 0 0 67 0 0 ... 0 0 0 0 0 0 0 0 3 72
/Assault Mode 0 0 0 0 0 0 0 2 0 0 ... 0 0 0 1 0 1 0 0 1 7
@Ignister 0 0 0 0 18 0 0 0 0 0 ... 0 0 0 0 0 0 0 0 0 18
A-to-Z 0 0 0 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0 0 16
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
sphinx 0 3 0 0 0 0 0 0 0 0 ... 0 6 0 0 0 0 0 0 0 9
sprout 0 0 0 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0 0 2
tellarknight 0 0 0 0 0 0 0 0 0 1 ... 0 0 0 0 0 15 0 1 0 17
with Eyes of Blue 0 0 0 0 0 0 0 0 0 0 ... 0 0 0 5 0 0 0 0 0 5
All 193 294 185 2 149 81 12 717 444 695 ... 138 213 71 577 95 1240 267 76 158 7245

647 rows × 26 columns

By property¶

archseries_crosstab_e = pd.crosstab(exploded_archseries['Archseries'],exploded_archseries['Property'], margins = True)
archseries_crosstab_e
Property Continuous Spell Card Continuous Trap Card Counter Trap Card Equip Spell Card Field Spell Card Normal Spell Card Normal Trap Card Quick-Play Spell Card Ritual Spell Card All
Archseries
A.I. 1 3 0 0 1 4 1 2 1 13
Abyss Actor 0 0 0 0 0 0 2 0 0 2
Abyss Script 1 0 0 0 0 4 0 1 0 6
Abyss- 0 1 0 3 0 0 3 0 0 7
Adamancipator 0 0 1 0 1 2 1 0 0 5
... ... ... ... ... ... ... ... ... ... ...
sphinx 0 1 0 0 0 0 0 0 0 1
tellarknight 0 0 0 1 1 0 0 2 0 4
with Chain 0 0 0 0 0 0 4 0 0 4
with Eyes of Blue 1 0 0 0 0 0 0 2 0 3
All 239 286 72 130 180 503 531 254 38 2233

396 rows × 10 columns

Artworks¶

print('Total number of cards with edited or alternate artworks:', formatted_full_df['Artwork'].count())
Total number of cards with edited or alternate artworks: 426
formatted_full_df[['Name','Password','TCG status','OCG status','Artwork']][formatted_full_df['Artwork'].notna()]
Name Password TCG status OCG status Artwork
51 Alluring Mirror Split 92881099 Unlimited Unlimited (Alternate, Edited)
60 Amazoness Spellcaster 81325903 Unlimited Unlimited (Edited,)
69 Ancient Gear Castle 92001300 Unlimited Unlimited (Edited,)
116 Arrivalrivals 29508346 Unlimited Unlimited (Alternate, Edited)
135 Axe of Despair 40619825 Unlimited Unlimited (Edited,)
... ... ... ... ... ...
11898 Soitsu 60246171 Unlimited Unlimited (Edited,)
11949 Stardust Dragon 44508094 Unlimited Unlimited (Alternate,)
11957 Storming Wynn 29013526 Unlimited Unlimited (Alternate, Edited)
11984 Thousand Dragon 41462083 Unlimited Unlimited (Alternate,)
11986 Toon Harpie Lady 64116319 Unlimited Unlimited (Edited,)

426 rows × 5 columns

artwork_value_counts = formatted_full_df['Artwork'].value_counts()
plt.figure(figsize=(20,8))
venn2(subsets = (artwork_value_counts[('Alternate',)], artwork_value_counts[('Edited',)],artwork_value_counts[('Alternate','Edited')]), set_labels = ('Alternate artwork', 'Edited artwork'))
plt.show()

By card type¶

artwork_crosstab = pd.crosstab(formatted_full_df['Artwork'], formatted_full_df['Card type'])
artwork_crosstab
Card type Monster Card Spell Card Trap Card
Artwork
(Alternate,) 81 4 6
(Alternate, Edited) 80 19 20
(Edited,) 111 62 43

By primary type¶

artwork_crosstab_b = pd.crosstab(formatted_full_df['Artwork'], formatted_full_df['Primary type'])
artwork_crosstab_b
Primary type Effect Monster Fusion Monster Link Monster Normal Monster Ritual Monster Synchro Monster Xyz Monster
Artwork
(Alternate,) 36 12 6 20 0 3 4
(Alternate, Edited) 39 6 7 20 4 0 4
(Edited,) 79 6 1 20 2 2 1

More granularity is unnecessary

Errata¶

print('Total number of cards with name or type errata:', formatted_full_df['Errata'].count())
Total number of cards with name or type errata: 1130
formatted_full_df[['Name','Password','TCG status','OCG status','Errata']][formatted_full_df['Errata'].notna()]
Name Password TCG status OCG status Errata
0 "A" Cell Breeding Device 34541863 Unlimited Unlimited (Name,)
9 7 Completed 86198326 Unlimited Unlimited (Type,)
10 The A. Forces 00403847 Unlimited Unlimited (Type,)
19 Abyss Playhouse - Fantastic Theater 77297908 Unlimited Unlimited (Name,)
43 Advanced Heraldry Art 61314842 Unlimited Unlimited (Name,)
... ... ... ... ... ...
12047 Winged Dragon, Guardian of the Fortress #1 87796900 Unlimited Unlimited (Name,)
12048 Winged Dragon, Guardian of the Fortress #2 57405307 Unlimited Unlimited (Name,)
12050 Winged Sage Falcos 87523462 Unlimited Unlimited (Name,)
12057 Wynn the Wind Charmer 37744402 Unlimited Unlimited (Name,)
12058 Wynn the Wind Charmer, Verdant 30674956 Unlimited Unlimited (Name,)

1130 rows × 5 columns

errata_value_counts = formatted_full_df['Errata'].value_counts()
plt.figure(figsize=(20,8))
venn2(subsets = (errata_value_counts[('Name',)], errata_value_counts[('Type',)],errata_value_counts[('Name','Type')]), set_labels = ('Name Errata', 'Type errata'))
plt.show()

By card type¶

errata_crosstab = pd.crosstab(formatted_full_df['Errata'], formatted_full_df['Card type'])
errata_crosstab
Card type Monster Card Spell Card Trap Card
Errata
(Name,) 311 57 51
(Name, Type) 74 21 2
(Type,) 396 209 9

By primary type¶

errata_crosstab_b = pd.crosstab(formatted_full_df['Errata'], formatted_full_df['Primary type'])
errata_crosstab_b
Primary type Effect Monster Fusion Monster Link Monster Normal Monster Ritual Monster Synchro Monster Xyz Monster
Errata
(Name,) 196 46 4 49 3 9 3
(Name, Type) 39 10 0 18 2 5 0
(Type,) 270 22 2 61 2 24 15

More granularity is unnecessary

By artwork¶

errata_crosstab_c = pd.crosstab(formatted_full_df['Artwork'], formatted_full_df['Errata'])
errata_crosstab_c
Errata (Name,) (Name, Type) (Type,)
Artwork
(Alternate,) 8 15 21
(Alternate, Edited) 9 6 13
(Edited,) 15 7 38

TCG & OCG status¶

TGC status¶

print('Total number of TCG status:', formatted_full_df['TCG status'].nunique())
Total number of TCG status: 7
formatted_full_df.groupby('TCG status', dropna=False).nunique()
Name Password Card type Property Primary type Secondary type Attribute Monster type Level/Rank ATK DEF Pendulum Scale Link Link Arrows Effect type Archseries Artwork Errata OCG status Modification date
TCG status
Forbidden 99 99 3 7 5 2 6 19 12 27 21 2 4 10 46 53 2 3 4 99
Illegal 38 0 3 3 5 0 6 14 5 11 12 2 2 2 6 7 0 1 1 38
Legal 20 0 1 0 1 0 5 11 5 6 7 0 0 0 0 13 2 1 1 20
Limited 81 81 3 7 6 3 6 15 9 20 20 3 2 2 42 40 3 3 4 81
Not yet released 8 8 3 6 2 0 2 2 1 2 1 0 1 1 6 4 0 0 1 8
Semi-Limited 9 9 3 4 2 0 3 3 1 3 3 0 0 0 8 8 1 1 3 9
Unlimited 11316 11313 3 9 7 6 7 24 14 80 75 13 6 60 342 1117 3 3 4 11216
NaN 505 417 3 9 8 3 7 24 12 54 39 6 4 8 97 114 1 1 4 505
formatted_full_df['TCG status'].value_counts(dropna = False).plot.bar(figsize = (18,6), logy=True, grid = True, rot=45)
plt.show()

By card type¶

# Remove unlimited
tcg_crosstab = pd.crosstab(formatted_full_df['Card type'], formatted_full_df['TCG status']).drop(['Unlimited'], axis=1)
tcg_crosstab
TCG status Forbidden Illegal Legal Limited Not yet released Semi-Limited
Card type
Monster Card 64 35 20 42 2 3
Spell Card 26 2 0 34 3 5
Trap Card 9 1 0 5 3 1
plt.figure(figsize = (12,6))
sns.heatmap(tcg_crosstab, annot=True, fmt="g", cmap='viridis', norm=LogNorm())
plt.show()

By monster type¶

# Remove unlimited
tcg_crosstab_b = pd.crosstab(formatted_full_df['Monster type'], formatted_full_df['TCG status']).drop(['Unlimited'], axis=1)
tcg_crosstab_b
plt.figure(figsize = (20,5))
sns.heatmap(tcg_crosstab_b.T, annot=True, fmt="g", cmap='viridis', square = True, norm=LogNorm())
plt.show()

By archseries¶

# Remove unlimited
tcg_crosstab_c = pd.crosstab(exploded_archseries['Archseries'].where(exploded_archseries['OCG status']!='Unlimited'), exploded_archseries['TCG status'], margins = True)
tcg_crosstab_c

OCG status¶

print('Total number of OCG status:', formatted_full_df['OCG status'].nunique())
formatted_full_df.groupby('OCG status', dropna=False).nunique()
formatted_full_df['OCG status'].value_counts(dropna = False).plot.bar(figsize = (18,6), logy=True, grid = True, rot=45)
plt.show()

By card type¶

# Remove unlimited
ocg_crosstab = pd.crosstab(formatted_full_df['Card type'], formatted_full_df['OCG status']).drop(['Unlimited'], axis=1)
ocg_crosstab
plt.figure(figsize = (12,6))
sns.heatmap(ocg_crosstab, annot=True, fmt="g", cmap='viridis', norm=LogNorm())
plt.show()

By monster type¶

# Remove unlimited
ocg_crosstab_b = pd.crosstab(formatted_full_df['Monster type'], formatted_full_df['OCG status']).drop(['Unlimited'], axis=1)
ocg_crosstab_b
plt.figure(figsize = (20,5))
sns.heatmap(ocg_crosstab_b.T, annot=True, fmt="g", cmap='viridis', square = True, norm=LogNorm())
plt.show()

By archseries¶

# Remove unlimited
ocg_crosstab_c = pd.crosstab(exploded_archseries['Archseries'].where(exploded_archseries['OCG status']!='Unlimited'), exploded_archseries['OCG status'], margins = True)
ocg_crosstab_c

TCG vs. OCG status¶

cg_crosstab = pd.crosstab(formatted_full_df['OCG status'],formatted_full_df['TCG status'], dropna=False, margins = False)
cg_crosstab
plt.figure(figsize = (10,8))
sns.heatmap(cg_crosstab, annot=True, fmt="g", cmap='viridis', square=True, norm=LogNorm())
plt.show()

HTML export¶

! jupyter nbconvert Cards.ipynb --to=HTML --TemplateExporter.exclude_input_prompt=True --TemplateExporter.exclude_output_prompt=True

Searches¶

formatted_full_df.loc[formatted_full_df['OCG status'] == 'Not yet released'].loc[formatted_full_df['TCG status'] == 'Not yet released']

Git¶

! git add .
! git commit -m {"Update-" + pd.Timestamp.now().strftime("%d%m%Y")}
! git push